// Copyright (c) Microsoft Corporation. All rights reserved.

using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.TeamFoundation.VersionControl.Client;
using Microsoft.TeamFoundation.VersionControl.Common;
using System.IO;
using System.Net;
using Microsoft.Teamfoundation.Migration.VersionControl.SharePoint.Versions;
using System.Xml;
using System.Web.Services.Protocols;
using System.Globalization;
using Microsoft.TeamFoundation.Migration.Toolkit;
using System.Diagnostics;
using Microsoft.TeamFoundation.Migration.Toolkit.VC;

namespace Microsoft.TeamFoundation.Migration.VersionControl.Wss
{
    public class WssToTfsMigrationEngine : SourceToTfsMigrationEngine
    {
        public WssToTfsMigrationEngine(VersionControlSession session, ChangeGroupingMananger manager)
            : base(session, manager)
        {
        }

        protected override void Add(IMigrationAction action, BatchingContext context)
        {
            try
            {
                base.Add(action, context);
            }
            catch (WssItemNotDownloadedException)
            {
                TraceManager.TraceWarning("Skipping non-downloadable item {0}", action.SourceItem.DisplayName);
                action.State = ActionState.Skipped;
            }
        }

        protected override void Edit(IMigrationAction action, BatchingContext context)
        {
            try
            {
                base.Edit(action, context);
            }
            catch (WssItemNotDownloadedException)
            {
                TraceManager.TraceWarning("Skipping non-downloadable item {0}", action.SourceItem.DisplayName);
                action.State = ActionState.Skipped;
            }
        }

        protected override void Download(IMigrationItem downloadItem, IMigrationAction action, string localPath)
        {
            WssMigrationItem wssItem = (WssMigrationItem)downloadItem;
            if (localPath.EndsWith("\\") || wssItem.CanonicalUrl.EndsWith("/")) // For folder, we just need to create the localpath
            {
                try
                {
                    Directory.CreateDirectory(localPath);
                }
                catch (Exception e)
                {
                    throw new WssItemNotDownloadedException(e.Message);
                }
                return;
            }
            wssItem.Download(localPath);

            switch (wssItem.DownloadStatus)
            {
                case HttpStatusCode.OK:
                    return;
                case HttpStatusCode.NotFound:
                    TraceManager.TraceWarning(
                        "The item {0} could not be downloaded because it no longer exists in WSS",
                        downloadItem.DisplayName);
                    Session.OnMigrationWarning(new VersionControlEventArgs(string.Format(WSS2TFSResources.Culture, WSS2TFSResources.ItemNoLongerExists, downloadItem.DisplayName), SystemType.Other));
                    addStubOnMissing(wssItem, localPath, 
                        action.Action == ChangeAction.Add);
                    return;
                case HttpStatusCode.UnsupportedMediaType:
                    TraceManager.TraceWarning(
                        "The item {0} could not be downloaded because it is an unsupported medium type",
                        downloadItem.DisplayName);
                    Session.OnMigrationWarning(new VersionControlEventArgs(string.Format(WSS2TFSResources.Culture, WSS2TFSResources.UnSupportedMediumType, downloadItem.DisplayName), SystemType.Other));
                    addStubOnMissing(wssItem, localPath, 
                        action.Action == ChangeAction.Add);
                    return;
                case HttpStatusCode.BadRequest:
                    TraceManager.TraceWarning(
                        "The item {0} could not be downloaded because a HTTP/400 (Bad Request) error was returned.",
                        downloadItem.DisplayName);
                    Session.OnMigrationWarning(new VersionControlEventArgs(string.Format(WSS2TFSResources.Culture, WSS2TFSResources.Http400, downloadItem.DisplayName), SystemType.Other));
                    addStubOnMissing(wssItem, localPath,
                        action.Action == ChangeAction.Add);
                    return;
                default:
                    string msg = string.Format(WSS2TFSResources.Culture, WSS2TFSResources.DownloadFailed, wssItem.DownloadStatus, wssItem.DisplayName);
                    Session.OnMigrationError(new VersionControlEventArgs(string.Format(WSS2TFSResources.Culture, WSS2TFSResources.DownloadFailed, wssItem.DownloadStatus, wssItem.DisplayName), SystemType.Other));
                    throw new WssItemNotDownloadedException(msg);
            }
        }

        private void addStubOnMissing(WssMigrationItem wssItem, string localPath, bool isAddAction)
        {
            // if we get a 404 on the Add version we should
            // add a dummy file.  There are cases where the
            // add revision is missing but the edits exist.
            // Specifically if an aspx file is checked in.

            if (isAddAction)
            {
                bool addStubVersionOnMissing =
                    this.Session.GetValue<bool>("AddStubVersionOnMissingAdd", false);

                if (addStubVersionOnMissing)
                {
                    TfsUtil.EnsurePathToFileExists(localPath);
                    using (StreamWriter sw = new StreamWriter(localPath))
                    {
                        sw.WriteLine("Wss to TFS Migration Error.  The following file returns a 404 error" +
                            " when downloading from Wss.  This is the first revision so a stub file is being added" +
                            " in it\'s place.");

                        sw.WriteLine(wssItem.DisplayName);
                    }
                }
                else
                {
                    string msg = string.Format(CultureInfo.InvariantCulture, "Error {0} downloading file: {1}.  To automatically create an stub revision in this situtation add a configuration setting named AddStubVersionOnMissingAdd with a value of \"true\"",
                        wssItem.DownloadStatus, wssItem.DisplayName);

                    throw new WssItemNotDownloadedException(msg);
                }
            }
            else
            {
                string msg = string.Format(CultureInfo.InvariantCulture, "The item in Wss failed to download with HTTP status {0}: {1}",
                    wssItem.DownloadStatus,
                    wssItem.DisplayName);

                throw new WssItemNotDownloadedException(msg);
            }
        }

        protected override bool IsOurTfsChanges(int changesetId)
        {
            Changeset c = TfsClient.GetChangeset(changesetId, false, false);
            return TfsUtil.IsOurTfsChange(c, CommentModifier);
        }
    }
}
